import { Awake1System } from "../../../../../Core/Module/EventSystem/IAwakeSystem";
import { DestroySystem } from "../../../../../Core/Module/EventSystem/IDestroySystem";
import { ExpandOf, FriendOf, ObjectSystemAttribute } from "../../../../../Decorator/Decorator";
import { NetClientComponent, NetClientComponentOnRead } from "../../../../Model/Client/Module/Message/NetClientComponent";
import { NetServices } from "../../../../../Core/Module/Network/NetServices";
import { Session } from "../../../../Model/Share/Module/Message/Session";
import { SessionIdleCheckerComponent } from "../../../../Model/Share/Module/Message/SessionIdleCheckerComponent";
import { SceneType } from "../../../../../Core/Module/Entity/SceneType";
import { TimeHelper } from "../../../../../Core/Module/Time/TimeHelper";
import { OpcodeHelper } from "../../../../Model/Share/Module/Message/OpcodeHelper";
import { EventSystem } from "../../../../../Core/Module/EventSystem/EventSystem";
import { Root } from "../../../../../Core/Module/Entity/Root";
import { WService } from "../../../../../Core/Module/Network/WService";

/**
 * 使用 Expand 扩展方法
 * 
 * 必须作出以下申明，才能调用对象的扩展方法
 */
declare module "../../../../Model/Client/Module/Message/NetClientComponent" {

    interface NetClientComponent {

        OnRead(channelId: number, actorId: number, message: number): void;
        OnError(channelId: number, error: number): void;
        Create(realIPEndPoint: string): Promise<Session>;
    }

}

@ExpandOf(NetClientComponent)
export class NetClientComponentSystem {

    private static OnRead(self: NetClientComponent, channelId: number, actorId: number, message: number): void {
        let session = self.GetChild<Session>(channelId);
        if (session == null) {
            return;
        }
        session.LastRecvTime = TimeHelper.ClientNow();
        OpcodeHelper.LogMsg(self.DomainZone(), message);
        let netClientComponentOnRead = new NetClientComponentOnRead();
        {
            netClientComponentOnRead.Session = session;
            netClientComponentOnRead.Message = message;
        }
        EventSystem.Instance.Publish(Root.Instance.Scene, netClientComponentOnRead);
    }

    private static OnError(self: NetClientComponent, channelId: number, error: number): void {
        let session = self.GetChild<Session>(channelId);
        if (session == null) {
            return;
        }
        session.Error = error;
        session.Dispose();
    }

    private static async Create(self: NetClientComponent, realIPEndPoint: string): Promise<Session> {
        let channelId = NetServices.Instance.CreateConnectChannelId();
        let session = self.AddChildWithId<Session, number>(Session, channelId, self.ServiceId);
        session.RemoteAddress = realIPEndPoint;
        // if (self.DomainScene().SceneType != SceneType.Benchmark) {
        //     session.AddComponent<SessionIdleCheckerComponent>(SessionIdleCheckerComponent);
        // }
        await NetServices.Instance.CreateChannel(self.ServiceId, session.Id, realIPEndPoint);
        return session;
    }

}

@FriendOf(NetClientComponent)
@ObjectSystemAttribute()
export class NetClientComponentAwake1System extends Awake1System<NetClientComponent, string> {

    Awake(self: NetClientComponent, ipEndPoint: string): void {
        self.ServiceId = NetServices.Instance.AddService(new WService());
        NetServices.Instance.RegisterReadCallback(self.ServiceId, self.OnRead.bind(self));
        NetServices.Instance.RegisterErrorCallback(self.ServiceId, self.OnError.bind(self));
    }

}

@FriendOf(NetClientComponent)
@ObjectSystemAttribute()
export class NetClientComponentDestroySystem extends DestroySystem<NetClientComponent> {

    Destroy(self: NetClientComponent): void {
        NetServices.Instance.RemoveService(self.ServiceId);
    }

}